﻿
#pragma once;


#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <deque>

#include "StringUtils.h"

namespace mvc
{
	typedef std::string Var;

	class Model;
	class Index
	{
		friend class Model;

	public:
		Index();

		bool isValid() const;

		int row() const;
		int col() const;


		const Model* model() const;

		const void* interPtr() const;

		Var data() const;

		Index parent() const;
		Index sibling(int row, int col) const;
		Index child(int row, int col) const;

		bool operator ==(const Index& index) const;
		bool operator !=(const Index& index) const;
		bool operator <(const Index& index) const;

	private:
		Index(int row, int col, const void* interPtr, const Model* model);

		int _row;
		int _col;

		const Model* _model;

		const void* _interPtr;
	};

	class Model
	{
	public:
		
		virtual bool hasIndex(int row, int col, const Index& parent = Index()) const = 0;

		virtual Index index(int row, int col, const Index& parent = Index()) const = 0;
		virtual Index sibling(int row, int col, const Index& idx) const = 0;

		virtual Index parent(const Index& child) const = 0;
		virtual bool hasChild(const Index& parent = Index()) const = 0;

		virtual int rowCount(const Index& parent = Index()) const = 0;
		virtual int colCount(const Index& parent = Index())const  = 0;

		virtual Var data(const Index& index)const = 0;
		virtual void setData(const Index& index, const Var& val) = 0;

		virtual void insertRows(int row, int count, const Index& parent = Index()) = 0;
		virtual void removeRows(int row, int count, const Index& parent = Index()) = 0;

		virtual void insertCols(int row, int count, const Index& parent = Index()) = 0;
		virtual void removeCols(int row, int count, const Index& parent = Index()) = 0;

	protected:
		inline Index createIndex(int row, int col, void* ptr = NULL) const;
	};
	
	/*
	class ListModel : public Model
	{
	public:
		ListModel() {}
		~ListModel() {}

		Index index(int row, int col, const Index& parent = Index()) const
		{
			return createIndex(row, col);
		}

		Index sibling(int row, int col, const Index& idx) const
		{
			return createIndex(row + 1, col);
		}

	private:
		Index parent(const Index& child) const { return Index(); }
		bool hasChild(const Index& parent = Index()) { return false; }
	};
	*/

	class View
	{
	public:
		void ShowInfo(const std::string& info)
		{
			printf("%s \n", info.c_str());
		}
	};

	class StringListModel : public Model
	{
		typedef std::deque<std::string> StringDeque;
	public:
		StringListModel();
		~StringListModel();

		bool hasIndex(int row, int col, const Index& parent = Index()) const;
		Index index(int row, int col, const Index& parent = Index()) const;
		Index sibling(int row, int col, const Index& idx) const;

		int rowCount(const Index& parent = Index()) const;
		int colCount(const Index& parent = Index()) const;

		Index parent(const Index& child) const;
		bool hasChild(const Index& parent = Index()) const;

		Var data(const Index& index) const;
		void setData(const Index& index, const Var& val);


		void insertRows(int row, int count, const Index& parent = Index());
		void removeRows(int row, int count, const Index& parent = Index());

		void insertCols(int row, int count, const Index& parent = Index()) {}
		void removeCols(int row, int count, const Index& parent = Index()) {}

	private:
		StringDeque m_StringList;
	};



	typedef std::string NodeData;

	class TreeNode
	{
	public:
		typedef std::vector<TreeNode*> TreeNodeList;

	public:

		TreeNode(const NodeData& data)
		{
			_data = data;
		}
		~TreeNode() 
		{
			for (auto node : children())
			{
				removeChild(node);
			}
		}

		const NodeData& data() const
		{
			return _data;
		}

		void setData(const NodeData& data)
		{
			_data = data;
		}

		TreeNode* parent() const
		{ 
			return _parent; 
		}

		void setParent(TreeNode* pNode)
		{
			_parent = pNode;
		}

		TreeNodeList& children()
		{
			return _children;
		}

		void addChild(TreeNode* pNode)
		{
			if (!pNode)
			{
				return;
			}

			pNode->setParent(this);

			_children.push_back(pNode);
		}
		
		void removeChild(TreeNode* pNode)
		{
			if (!pNode)
			{
				return;
			}

			auto it = std::find(_children.begin(), _children.end(), pNode);
			if (it==_children.end())
			{
				return;
			}

			delete pNode;
			
			_children.erase(it);
		}

		void traverse(TreeNode* pNode, TreeNodeList& nodeList)
		{
			nodeList.push_back(pNode);

			for (auto node : pNode->children())
			{
				traverse(node, nodeList);
			}
		}

	private:
		NodeData _data;

		TreeNode* _parent;
		TreeNodeList _children;
	};

	class StringTreeModel : public Model
	{

	public:
		StringTreeModel();
		~StringTreeModel();

		bool hasIndex(int row, int col, const Index& parent = Index()) const;
		Index index(int row, int col, const Index& parent = Index()) const;
		Index parent(const Index& child) const;
		Index sibling(int row, int col, const Index& idx) const;

		int rowCount(const Index& parent = Index()) const;
		int colCount(const Index& parent = Index()) const;

		bool hasChild(const Index& parent = Index()) const;

		Var data(const Index& index) const;
		void setData(const Index& index, const Var& val);


		void insertRows(int row, int count, const Index& parent = Index());
		void removeRows(int row, int count, const Index& parent = Index());

		void insertCols(int row, int count, const Index& parent = Index());
		void removeCols(int row, int count, const Index& parent = Index());

	private:
		TreeNode* _root;

		TreeNode* _getTreeNode(const Index& index) const;
	};
}


extern void test_mvc();